﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel;

namespace BattleThis.Helpers
{
	/// <summary>
	/// Extending the default modelbinder.
	/// </summary>
	public class ExtendedModelBinder : DefaultModelBinder
	{
		/// <summary>
		/// Sets the specified property by using the specified controller context, binding context, and property value.
		/// </summary>
		/// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param>
		/// <param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param>
		/// <param name="propertyDescriptor">Describes a property to be set. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value.</param>
		/// <param name="value">The value to set for the property.</param>
		protected override void SetProperty( ControllerContext controllerContext,
											 ModelBindingContext bindingContext,
											 PropertyDescriptor propertyDescriptor, object value )
		{
			if( IsSelectionList(propertyDescriptor)  )
			{
				BindSelectionList( bindingContext, propertyDescriptor );
				return;
			}

			base.SetProperty( controllerContext, bindingContext, propertyDescriptor, value );
		}

		/// <summary>
		/// Binds the selection list.
		/// </summary>
		/// <param name="bindingContext">The binding context.</param>
		/// <param name="propertyDescriptor">The property descriptor.</param>
		private void BindSelectionList( ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor )
		{
			var valueKey = string.IsNullOrEmpty( bindingContext.ModelName ) ? propertyDescriptor.Name
                : string.Format( "{0}.{1}", bindingContext.ModelName, propertyDescriptor.Name );

			bindingContext.ModelState[ valueKey ].Errors.Clear();

			var listItemValue = bindingContext.ValueProvider.GetValue( valueKey ).AttemptedValue;
			var items = propertyDescriptor.GetValue( bindingContext.Model ) as IEnumerable<SelectListItem>;
			var item = new SelectListItem { Value = listItemValue, Selected = true };

			if( items == null || items.Count()<= 0 )
			{
				propertyDescriptor.SetValue( bindingContext.Model, new SelectListItem[] { item } );
			}
			else
			{
				items.Where( i => i.Value == listItemValue ).First().Selected = true;
			}

			return;
		}

		/// <summary>
		/// Determines whether [is selection list] [the specified property descriptor].
		/// </summary>
		/// <param name="propertyDescriptor">The property descriptor.</param>
		/// <returns>
		///   <c>true</c> if [is selection list] [the specified property descriptor]; otherwise, <c>false</c>.
		/// </returns>
		protected bool IsSelectionList(PropertyDescriptor propertyDescriptor)
		{ 
			return propertyDescriptor.PropertyType.IsAssignableFrom( typeof( IEnumerable<SelectListItem> ));
		}
	}
}